package com.atguigu.gulimall.order;

import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * 使用RabbitMQ
 * 1、引入amqp场景;RabbitAutoConfiguration就会自动生效
 * 2、给容器中自动配置了
 *      RabbitTemplate、AmqpAdmin、CachingConnectionFactory、RabbitMessagingTemplate
 * 3、@EnableRabbit:
 *      给配置文件中配置 spring.rabbitmq 信息
 *
 * Seata控制分布式事务
 *  1）、每一个微服务必须创建undo_Log
 *  2）、安装事务协调器：seate-server
 *  3）、整合
 *      1、导入依赖
 *      2、解压并启动seata-server：
 *          registry.conf:注册中心配置    修改 registry ： nacos
 *      3、所有想要用到分布式事务的微服务使用seata DataSourceProxy 代理自己的数据源
 *      4、每个微服务，都必须导入   registry.conf   file.conf
 *          vgroup_mapping.{application.name}-fescar-server-group = "default"
 *      5、启动测试分布式事务
 *      6、给分布式大事务的入口标注@GlobalTransactional
 *      7、每一个远程的小事务用@Trabsactional
 */

/**
 * 定制RabbitTemplate
 * 1、消息正确到达服务器
 *      1、spring.rabbitmq.publisher-confirms=true
 *      2、设置确认回调setConfirmCallback
 * 2、消息正确到达队列
 *      1、spring.rabbitmq.publisher-returns=true
 *          spring.rabbitmq.template.mandatory=true
 *      2、设置确认回调setReturnCallback
 *
 *  3、消费端确认。（保证每个消息被正确消费，此时broker才可以删除这个消息）
 *       1、默认是自动确认的，只要消息接收到，客户端会自动确认，服务端就会移除这个消息。
 *       问题：
 *      我们收到很多消息，自动回复给mq服务器ack，只有部分消息处理成功，宕机了，发生消息丢失。
 *     （默认为只要消息到达后端服务器，服务器就会回复ack消息给mq服务器，而不管后端服务器是否正确处理该消息。mq服务器得到ack消息就会将消息删除，造成消息丢失）
 *      解决办法：消费者手动确认。只要我们没有告诉MQ，货物被签收，没有ack，消息就一直是unack状态。即使Consumer宕机，消息不会丢失，会重新变为
 *       Ready，下一次有新的Consumer连接进来就发给他。
 *       手动确认
 *      1、spring.rabbitmq.listener.simple.acknowledge-mode=manual
 *      2、利用channel来确认：  channel.basicAck签收：业务成功完成就应该签收
 *                           channel.basicNack拒签：业务失败，拒签。
 *
 *
 *
 *
 */

/**
 * 1、如果方法a、b、c都在同一个service里面，事务传播行为不生效，共享一个事务
 * 	原理：事务是用代理对象来控制的，内部调用b(),c(),就相当于直接调用没有经过事务【绕过了代理对象】
 * 	解决：不能使用this.b()；也不能注入自己【要使用代理对象来调用事务方法】
 *
 *
 * @Transactional(timeout=30)
 * public void a() {
 * 	b();// a事务传播给了b事务，并且b事务的设置失效
 * 	c();// c单独创建一个新事务
 * }
 *
 * @Transactional(propagation = Propagation.REQUIRED, timeout=2)
 * public void b() {
 *
 * }
 *
 * @Transactional(propagation = Propagation.REQUIRES_NEW)
 * public void c() {
 *
 * }
 */

/**
 * 具体步骤：
 * 1、引入aop依赖
 *          引入aop，解决本地事务失效问题
 *         <dependency>
 *             <groupId>org.springframework.boot</groupId>
 *             <artifactId>spring-boot-starter-aop</artifactId>
 *         </dependency>
 *
 * 2、开启动态代理【默认使用jdk动态代理，需要有接口】
 * @EnableAspectJAutoProxy(exposeProxy = true)     //开启了aspect动态代理模式,对外暴露代理对象
 * 好处：cglib继承的方式完成动态代理
 * exposeProxy = true：对外暴露代理对象
 *
 * 3、获取动态代理对象
 * OrderServiceImpl orderService = (OrderServiceImpl)AopContext.currentProxy();
 * orderService.b();
 * orderService.c();
 */

@EnableFeignClients
@EnableRabbit
@SpringBootApplication
@EnableDiscoveryClient
public class GulimallOrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallOrderApplication.class, args);
    }

}
